﻿using IniReadWrite;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using VisionRoc.Tool;

namespace VisionRoc.Core
{
    public class TCPClient
    {
        public delegate void ReceiveMessage(Socket socketClient);
        ReceiveMessage Receive;
        public string ClientrPath;

        public TCPClient(string _Path, ReceiveMessage _receive)
        {
            //判断文件路径是否存在
            if (!Directory.Exists(_Path))
            {
                Directory.CreateDirectory(_Path);
            }
            ClientrPath = _Path + "\\TCPClient.ini";
            if (File.Exists(ClientrPath))
            {
                ReadParameter();
                Receive = _receive;
                Connect();
            }
            else
            {
                IP = "127.0.0.1";
                Port = 8001;
                Receive = _receive;
                Connect();
            }
        }

        /// <summary>
        /// 连接远程服务器IP
        /// </summary>
        public string IP;

        /// <summary>
        /// 连接远程服务器端口号
        /// </summary>
        public int Port;

        /// <summary>
        /// 连接服务器状态  True为连接成功 False为连接失败
        /// </summary>
        public bool ConnectState = false;

        /// <summary>
        /// 是否进行断线重新连接  1为进行断线重新连接  2 为不进行断线重新连接
        /// </summary>
        public int ReconnectState;

        /// <summary>
        /// 可判断是否接收到服务器发来的消息,True是接收到消息。需要手动恢复false。
        /// </summary>
        public bool RecevieState = false;

        /// <summary>
        /// 接收客户端发来的消息
        /// </summary>
        public string Message;

        /// <summary>
        /// 取消断线重新连接线程
        /// </summary>
        private int CL_State;

        private Socket socketClient;

        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <returns></returns>
        public bool Connect()
        {
            if (PingIP(IP))
            {
                CL_State = 2;
                // 第一步调用Socket() 函数创建一个用于通信的套接字。
                socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                // 第二步 给已经创建的套接字绑定一个端口号，这一般通过网络套接口地址和调用Bind() 函数来实现。
                IPEndPoint iPEnd = new IPEndPoint(IPAddress.Parse(IP), Port);
                try
                {
                    //第三部调用connect() 函数来创立连接
                    //socketClient.Connect(iPEnd);
                    socketClient.ConnectAsync(iPEnd).Wait(1000);
                }
                catch
                {
                    if (ReconnectState == 1)
                    {
                        Reconnection();
                    }
                    //连接服务器失败
                    ConnectState = false;
                    Global.AddLogInfoEvent(LogLevel.Warn, " 连接服务器失败");
                    return false;
                }

                if (socketClient.Connected)
                {
                    Task.Run(new Action(() =>
                    {
                        Receive.Invoke(socketClient);
                        //CheckReceiveMsg();
                    }));
                    ConnectState = true;
                    Global.AddLogInfoEvent(LogLevel.OK, " 连接服务器成功。");
                    return true;
                }
                else
                {
                    if (ReconnectState == 1)
                    {
                        Reconnection();
                    }
                    ConnectState = false;
                    Global.AddLogInfoEvent(LogLevel.Warn, " 连接服务器失败。");
                    //连接服务器失败
                    return false;
                }
            }
            else
            {
                ConnectState = false;
                Global.AddLogInfoEvent(LogLevel.Warn, " 连接服务器失败,IP为Ping通请检查网线");
                return false;
            }

        }

        /// <summary>
        /// 断线重新连接方法
        /// </summary>
        public void Reconnection()
        {
            Task.Run(new Action(() =>
            {
                while (true)//循环
                {
                    try
                    {
                        if (ReconnectState == 1)
                        {
                            if (socketClient != null)
                            {
                                socketClient.Close();//先关闭
                            }
                            Global.AddLogInfoEvent(LogLevel.Warn, "断线重新连接中········！");
                            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                            IPEndPoint iPEnd = new IPEndPoint(IPAddress.Parse(IP), Port);
                            socketClient.ConnectAsync(iPEnd).Wait(1000);
                            if (socketClient.Connected)
                            {
                                Global.AddLogInfoEvent(LogLevel.OK, "服务器重新连接成功！");
                                Task.Run(new Action(() =>
                                {
                                    Receive.Invoke(socketClient);
                                    //CheckReceiveMsg();
                                }));
                                ConnectState = true;
                                break;
                            }
                            if (CL_State == 1)
                            {
                                break;
                            }
                        }
                        else
                        {
                            Global.AddLogInfoEvent(LogLevel.Info, "取消断线重新连接·······！");
                            break;
                        }

                    }
                    catch
                    {
                        Global.AddLogInfoEvent(LogLevel.Info, "取消断线重新连接·······！");
                        break;
                    }
                }
            }));
        }

        /// <summary>
        /// 接收服务器发来的消息
        /// </summary>
        private void CheckReceiveMsg()
        {

            while (true)
            {
                //创建一个缓冲区
                byte[] buffer = new byte[1024 * 1024];
                int Length = -1;
                string client = socketClient.RemoteEndPoint.ToString();
                //第四部调用读写函数发送或者接收
                try
                {
                    Length = socketClient.Receive(buffer);
                }
                catch
                {
                    RecevieState = false;
                    if (ReconnectState == 1)
                    {
                        Reconnection();
                    }

                    Global.AddLogInfoEvent(LogLevel.Warn, "与服务器断开连接");
                    break;
                }

                if (Length > 0)
                {
                    RecevieState = true;
                    //处理
                    Message = Encoding.Default.GetString(buffer, 0, Length);
                    Global.AddLogInfoEvent(LogLevel.Info, $"接收服务器：{client}发送来的消息:{Message} ");
                }
                else
                {
                    RecevieState = false;
                    //服务器断开连接
                    Global.AddLogInfoEvent(LogLevel.Warn, "与服务器断开连接");
                    if (ReconnectState == 1)
                    {
                        Reconnection();
                    }
                    break;
                }

            }
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="Msg"></param>
        public void Send(string Msg)
        {
            if (socketClient != null)
            {
                if (socketClient.Connected)
                {
                    try
                    {
                        socketClient.Send(Encoding.Default.GetBytes(Msg.Trim()));
                        Global.AddLogInfoEvent(LogLevel.OK, $"发送至服务器Info：{Msg}");

                    }
                    catch (Exception ex)
                    {
                        Global.AddLogInfoEvent(LogLevel.Error, $"发送异常报错 已写入文本");
                        TxtAPI.WriteLogTxt(Global.m_ImageSavePath.LogPath, ex.ToString());
                    }

                }
                else
                {
                    Global.AddLogInfoEvent(LogLevel.Info, $"没有连接服务器，消息未发送。");
                }

            }
            else
            {
                Global.AddLogInfoEvent(LogLevel.Warn, $"客户端对象为空，请连接服务器。");
            }
        }

        /// <summary>
        /// 关闭客户端
        /// </summary>
        public void CloseClient()
        {
            try
            {

                CL_State = 1;
                if (socketClient == null)
                {
                    return;
                }
                if (socketClient.IsBound && socketClient.Connected)
                {
                    socketClient.Shutdown(SocketShutdown.Both);
                }
                socketClient.Close();
                socketClient.Dispose();
                socketClient = null;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

        }

        /// <summary>
        /// Ping 当前IP 是否Ping 通
        /// </summary>
        /// <param name="IP"></param>
        /// <returns></returns>
        public static bool PingIP(string IP)
        {
            try
            {
                Ping ping = new Ping();
                PingReply pingReply = ping.Send(IP); // m_strIP
                if (pingReply.Status == IPStatus.Success)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 保存参数
        /// </summary>
        public void WriteParameter()
        {
            IniAPI.INIWriteValue(ClientrPath, "IP", "IP", IP);
            IniAPI.INIWriteValue(ClientrPath, "Port", "Port", Port.ToString());
            IniAPI.INIWriteValue(ClientrPath, "ReconnectState", "state", ReconnectState.ToString());
        }

        /// <summary>
        /// 读取参数
        /// </summary>
        public void ReadParameter()
        {
            IP = IniAPI.INIGetStringValue(ClientrPath, "IP", "IP", "0");
            Port = Convert.ToInt32(IniAPI.INIGetStringValue(ClientrPath, "Port", "Port", "0"));
            ReconnectState = Convert.ToInt32(IniAPI.INIGetStringValue(ClientrPath, "ReconnectState", "state", "0"));
        }

        ~TCPClient()
        {
            CloseClient();
        }


    }
}
